//=============================================================================
//     _   _                               ____                _  _          
//    | | | |  __ _  _ __   _ __   _   _  / ___|  _ __   _ __ (_)| |_   ___ 
//    | |_| | / _` || '_ \ | '_ \ | | | | \___ \ | '_ \ | '__|| || __| / _ \
//    |  _  || (_| || |_) || |_) || |_| |  ___) || |_) || |   | || |_ |  __/
//    |_| |_| \__,_|| .__/ | .__/  \__, | |____/ | .__/ |_|   |_| \__| \___|
//                  |_|    |_|     |___/         |_|                         
//
//                     HappySprite - We make sprites happy
//
// Copyright (c) 2007 by Tank Monkey Games
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//=============================================================================

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace HappySprite.Graphics
{
    public class QuadEffect
    {
        VertexDeclaration vertexDeclaration;
        VertexBuffer buffer;
        Effect effect;
        EffectParameter worldParam;
        EffectParameter viewParam;
        EffectParameter projectionParam;
        EffectParameter textureParam;
        EffectParameter imageMapParam;
        EffectParameter tintParam;

        public Matrix Projection
        {
            get { return projectionParam.GetValueMatrix(); }
            set { projectionParam.SetValue(value); }
        }

        public Matrix View
        {
            get { return viewParam.GetValueMatrix(); }
            set { viewParam.SetValue(value); }
        }

        public Matrix World
        {
            get { return worldParam.GetValueMatrix(); }
            set { worldParam.SetValue(value); }
        }

        public Texture2D Texture
        {
            get { return textureParam.GetValueTexture2D(); }
            set { textureParam.SetValue(value); }
        }

        public Vector4 ImageMap
        {
            get { return imageMapParam.GetValueVector4(); }
            set { imageMapParam.SetValue(value); }
        }

        public Color Tint
        {
            get { return new Color(tintParam.GetValueVector4()); }
            set { tintParam.SetValue(value.ToVector4()); }
        }

        internal void Render()
        {
            GraphicsDevice device = Global.Renderer.Graphics.GraphicsDevice;

            // Set the primitive
            device.VertexDeclaration = vertexDeclaration;
            device.Vertices[0].SetSource(buffer, 0, VertexPositionTexture.SizeInBytes);

            effect.CommitChanges();

            // Begin the effect
            effect.Begin(SaveStateMode.SaveState);

            try
            {
                for (int i = 0; i < effect.CurrentTechnique.Passes.Count; i++)
                {
                    EffectPass pass = effect.CurrentTechnique.Passes[i];
                    pass.Begin();

                    // Draw the quad primitive
                    device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);

                    pass.End();
                }
            }
            finally
            {
                effect.End();
            }
        }

        internal void Initialize()
        {
            GraphicsDevice device = Global.Renderer.Graphics.GraphicsDevice;

            // The vertex declaration
            vertexDeclaration = new VertexDeclaration(device, VertexPositionTexture.VertexElements);

            // The vertex buffer
            buffer = new VertexBuffer(device, typeof(VertexPositionTexture), 4, BufferUsage.WriteOnly);

            VertexPositionTexture[] data = new VertexPositionTexture[4];

            data[0].Position = new Vector3(-1f, 1f, 0f);
            data[0].TextureCoordinate = new Vector2(0f, 0f);
            data[1].Position = new Vector3(1f, 1f, 0f);
            data[1].TextureCoordinate = new Vector2(1f, 0f);
            data[2].Position = new Vector3(-1f, -1f, 0f);
            data[2].TextureCoordinate = new Vector2(0f, 1f);
            data[3].Position = new Vector3(1f, -1f, 0f);
            data[3].TextureCoordinate = new Vector2(1f, 1f);

            buffer.SetData<VertexPositionTexture>(data);

            // The effect
            string shaderCode;
            string resource = "HappySprite.Graphics.Quad.QuadEffect.fx";
            Assembly assembly = GetType().Assembly;

            using (StreamReader reader = new StreamReader(assembly.GetManifestResourceStream(resource)))
            {
                shaderCode = reader.ReadToEnd();
            }

            CompiledEffect compiledEffect = Effect.CompileEffectFromSource(shaderCode, null, null, CompilerOptions.None, TargetPlatform.Windows);
            effect = new Effect(device, compiledEffect.GetEffectCode(), CompilerOptions.None, null);

            // The effect parameters
            worldParam = effect.Parameters["world"];
            viewParam = effect.Parameters["view"];
            projectionParam = effect.Parameters["projection"];
            textureParam = effect.Parameters["skinTexture"];
            imageMapParam = effect.Parameters["imageMap"];
            tintParam = effect.Parameters["tint"];
        }
    }
}
